package com.oro.domain;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.Transient;

import org.hibernate.validator.NotNull;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.UserDetails;

@Entity
public class User extends Contatto implements Serializable, UserDetails {

	private static final long serialVersionUID = 1L;

	@NotNull
	private String confirmPassword;

	@NotNull
	private String password;

	@ManyToMany
	// Uni-directional
	@JoinTable
	private List<com.oro.domain.Authority> roles;

	@NotNull
	@Column(unique = true)
	private String username;

	public User() {
		super();
		roles = new ArrayList<com.oro.domain.Authority>();
		roles.add(Authority.ANONYMOUS);
	}

	public User(String username, String password) {
		this();
		this.username = username;
		this.password = password;
		this.confirmPassword = password;
		setFirstName(username);
		setSurname(username);
	}

	public User(String username, String password, Authority au) {
		this(username, password);
		this.addAuthority(au);
	}

	public User(String username, String password,
			List<com.oro.domain.Authority> aus) {
		this(username, password);
		this.roles = aus;
	}

	public User(String username, String password, String au) {
		this(username, password);
		this.addAuthority(au);
	}

	/**
	 * Add the authority only if the user hasn't that authority yet.
	 * 
	 * @return true if the authority was added; false otherwise
	 */
	public boolean addAuthority(Authority au) {
		if (au == null)
			return false;
		if (!this.hasAuthority(au)) {
			roles.add(au);
			return true;
		} else
			return false;
	}

	/**
	 * Add the authority only if the user hasn't that authority yet.
	 * 
	 * @return true if the authority was added; false otherwise
	 */
	public boolean addAuthority(String au) {
		if (au == null)
			return false;
		if (!this.hasAuthority(au)) {
			this.addAuthority(Authority.getAuthority(au));
			return true;
		} else
			return false;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o)
			return true;
		if (!(o instanceof User))
			return false;
		User u = (User) o;
		if (getId() != null)
			return getId().equals(u.getId());
		else
			return username == u.getUsername();
	}

	// UserDetails method

	public boolean equals(User user) {
		if (getId() != null)
			return (this.getId().equals(user.getId()));
		else
			return this.username == user.getUsername();
	}

	@Override
	@Transient
	public List<GrantedAuthority> getAuthorities() {
		List<GrantedAuthority> gas = new ArrayList<GrantedAuthority>();
		for (com.oro.domain.Authority au : roles) {
			gas.add(new GrantedAuthorityImpl(au.getRole()));
		}
		return gas;
	}

	public String getConfirmPassword() {
		return confirmPassword;
	}

	@Override
	public String getPassword() {
		return this.password;
	}

	public List<com.oro.domain.Authority> getRoles() {
		return roles;
	}

	@Override
	public String getUsername() {
		return this.username;
	}

	public boolean hasAuthority(Authority au) {
		return roles.contains(au);
	}

	// UserDetails method

	public boolean hasAuthority(String au) {
		for (Authority a : roles) {
			if (a.getRole().equals(au))
				return true;
		}
		return false;
	}

	// UserDetails method

	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	// UserDetails method

	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	// UserDetails method

	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	@Override
	public boolean isEnabled() {
		return true;
	}

	/**
	 * Remove the given authority only if the user already has it
	 * 
	 * @return true if the user had the authority and the authority was thus
	 *         removed; false otherwise.
	 */
	public boolean removeAuthority(Authority a) {
		return roles.remove(a);
	}

	/**
	 * Remove the given authority only if the user already has it
	 * 
	 * @return true if the user had the authority and the authority was thus
	 *         removed; false otherwise.
	 */
	public boolean removeAuthority(String role) {
		for (Authority au : roles) {
			if (au.getRole().equals(role)) {
				roles.remove(au);
				return true;
			}
		}
		return false;
	}

	public void setAuthorities(Collection<GrantedAuthority> grauthorities) {
		if (!grauthorities.isEmpty()) {
			List<Authority> newRoles = new ArrayList<Authority>();
			for (GrantedAuthority grau : grauthorities) {
				newRoles.add(new Authority(grau.getAuthority()));
			}
			this.roles = newRoles;
		}
	}

	public void setConfirmPassword(String confirmPassword) {
		this.confirmPassword = confirmPassword;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public void setRoles(List<com.oro.domain.Authority> roles) {
		this.roles = roles;
	}

	public void setUsername(String username) {
		this.username = username;
	}

}
